////////////////////////////////////////////////////////////////////////////////
//
//  MICROSOFT CORPORATION
//  Copyright (c) Microsoft Corporation.
//  All Rights Reserved.
//
//  NOTICE: Microsoft Confidential. Intended for Internal Use Only.
//
////////////////////////////////////////////////////////////////////////////////

package com.msn.beet.tracking.atlas
{

import com.msn.beet.tracking.ITrackModel;
import com.msn.beet.tracking.atlas.AtlasModel;
import com.msn.beet.tracking.atlas.IAtlasTrackAction;

/**
 * Use this class to access a value from the senders model by passing the
 * constant COLLECTION as the 'action', and the collection key as 'id'.
 * Otherwise use a subclass to specify different track types,
 * collection accessors and collection parsing hooks.
 */
public class AtlasTrackAction implements IAtlasTrackAction
{
    include "../../core/Version.as";

    /**
    * Keyword used indicate that model's collection should be accessed
    * using 'id' as key
    */
    public static const COLLECTION:String = "collection";

    /**    Keyword used by atlas server to parse values     */
    protected static const ACTION:String = "action";

    /**    Keyword used by atlas server to parse values     */
    protected static const ACTION_NAME:String = "actionname";

    /**    Keyword used by atlas server to parse values     */
    protected  const SECTION:String = "section";

    /**    Keyword used by atlas server to parse values     */
    protected static const LOCATION:String = "location";

    protected var action:String;
    protected var id:String;

    /**
     * Use this class to access a collection of preformatted tracking
     * strings in AtlasSender's model, otherwise it should be subclassed.
     *
     * @param action    The action type, if string 'collection' is passed,
     *                  the tracking values will be retrieved from the
     *                  collection in Senders model.
     *
     * @param id        The action name to be included in the tracking
     *                  string or the id to look up in the collection
     */
    public function AtlasTrackAction(id:String, action:String = null)
    {
        this.id = id;
        this.action = action;
    }

    /**
     * Strategy for AtlasSender to assemble track strings. Uses
     * 'assembleForAtlas' to create the string, unless _action ==
     * "collection", in which case the value will be looked up in the
     * senders model, and passed through 'collectionHook'.
     *
     * @param model
     * @return
     */
    public function parseForAtlas(model:ITrackModel):String
    {
        if (action == COLLECTION)
        {
            return collectionHook(model.collection[this.id])
        }
        else
        {
            return assembleForAtlas(model);
        }
    }

    /**
     * Helper for building out common tracking strings, override to include
     * additional parameters.
     * @param model
     * @return
              * @example
     <listing version="3.0">
        override protected function assembleForAtlas(
           model:ITrackModel):String
        {
            var track:String = model.baseString +
                join("action", this._action) +
                join("actionname", this._videoTitle) +
                join("location", model.location) +
                join("section", model.section) +
                join("var1", this.time) +
                join("var2", model.videotime) +
                "?" + Math.random();

            return track;
        }
     </listing>
     */
    protected function assembleForAtlas(model:ITrackModel):String
    {
        var atlasModel:AtlasModel = AtlasModel(model);

        var track:String = atlasModel.baseString +
            join(this.action, ACTION) +
            join(this.id, ACTION_NAME) +
            join(atlasModel.location, LOCATION) +
            join(atlasModel.section, SECTION) +
            "?" + Math.random();

        return track;
    }

    /**
     * Override this to specify how values from collection dictionary are
     * processed and built into a tracking string. Default behavior returns
     * dictionary result as string.
     * @param value
     * @return
     * @example
     <listing version="3.0">
        // Build track out of returned value object from collection:
        // {"action":"CLICK"}, {"actionName":"DRAG"},
        // {"customTag":"CUSTOM_VALUE"}
         override protected function collectionHook(value:*):String
        {
             if (value is myStruct)
             {
                 var track:String = _baseString;
                var args:Array = value.args;

                for (var i:int; i < args.length; i++)
                {
                    for (var p:String in args[i])
                    {
                        track += join(p, args[i][p]);
                    }
                }

                return track;
            }
            return null;
         }
     </listing>
     */
    protected function collectionHook(value:*):String
    {
        return value as String;
    }

    /**
     * Strategy for AtlasSenderJS to assemble track strings. Uses
     * 'assembleForAtlasJS' to create the string, unless _action ==
     * "collection" and _id != null, in which case the value will be looked
     * up in the senders model, and passed through 'collectionHookJS'.
     *
     * Typical formatting for Atlas.js is "action|id|section|location"
     *
     * @param model
     * @return
     * @example
     <listing version="3.0">
             return this._action + "|" + this._id + "|" + model.section +
                 "|" + model.location;
     </listing>
     */
    public function parseForAtlasJS(model:ITrackModel):String
    {
        if (action == null)
        {
            return id;
        }
        else if (action == COLLECTION)
        {
            return collectionHookJS(model.collection[id])
        }
        else
        {
            return assembleForAtlasJS(model);
        }
    }

    /**
     * Helper for building out strings in most common format, override to
     * specify different pattern.
     * @example
     <listing version="3.0">
        override protected function assembleForAtlasJS(
            model:ITrackModel):String
        {
             return super._action + "|" + super._id + "|" + model.section +
                this.param +"|"+ model.location;
        }
     </listing>
     */
    protected function assembleForAtlasJS(model:ITrackModel):String
    {
        return this.action + "|" + this.id + "|" + model.section + "|" +
               model.location;
    }

    /**
     * Override this to specify how values from collection dictionary are
     * processed and built into a tracking string. Default behavior returns
     * dictionary result as string.
     */
    protected function collectionHookJS(value:*):String
    {
        return value as String;
    }

    /**
     * Function used by AtlasSender strategy for creating singles or doubles
     * in atlas query format, use 'join("", "single")' to create a single
     * value. All second 'value' params are run through
     * 'cleans'.
     *
     * @param tag   Atlas key identifier.
     * @param value Value to be passed to Atlas.
     */
    protected function join(value:String, tag:String = ""):String
    {
        if (value == null)
        {
            throw new ReferenceError(
                "Attempted access of unitialized value.");
        }
        else if (value == "")
        {
            return "";
        }
        else
        {
            return tag + "." + cleanse(value) + "/";
        }
    }

    /**
     * Function used by AtlasSender strategy for replacing \?&.# with '_',
     * use to groom dynamic values before incorporating into tracking query
     * string.
     */
    protected function cleanse(value:String):String
    {
        return value.replace(/\/|\?|&|\.|#/g, "_");
    }

}

}
